<template>
	<div class="sc-upload" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)" :style="style">
		<div v-if="tempImg || img" class="sc-upload-file">
			<div class="mask" v-if="!disabled">
				<span class="del" @click.stop="del"><i class="el-icon-delete"></i></span>
			</div>
			<el-image v-if="fileIsImg" class="image" :src="tempImg || img" :preview-src-list="[img]" hide-on-click-modal append-to-body :z-index="9999"></el-image>
			<a v-else :href="img" class="file" target="_blank"><i class="el-icon-document"></i></a>
		</div>
		<div v-else class="sc-upload-uploader" @click="fileSelect && showfileSelect()">
			<el-upload ref="upload" class="uploader" :disabled="fileSelect" :auto-upload="!cropper" :on-change="change" :accept="accept" :action="action" :show-file-list="false" :before-upload="before" :on-success="success" :on-error="error" :http-request="request">
				<slot>
					<div class="file-empty">
						<i :class="icon"></i>
						<h4 v-if="title">{{title}}</h4>
					</div>
				</slot>
			</el-upload>
		</div>
		<el-dialog title="剪裁" :close-on-click-modal="false" v-model="cropperDialogVisible" :width="580" destroy-on-close>
			<sc-cropper :src="cropperImg" :compress="compress" :aspectRatio="aspectRatio" :cWidth="cWidth" :cHeight="cHeight" ref="cropper"></sc-cropper>
			<template #footer>
				<el-button @click="cropperDialogVisible=false" >取 消</el-button>
				<el-button type="primary" @click="cropperSave">确 定</el-button>
			</template>
		</el-dialog>
		<el-dialog title="打开" :close-on-click-modal="false" v-model="fileSelectDialogVisible" :width="880" destroy-on-close>
			<sc-file-select @submit="fileSelectSubmit">
				<template #do>
					<el-button @click="fileSelectDialogVisible=false" >取 消</el-button>
				</template>
			</sc-file-select>
		</el-dialog>
		<el-input v-model="img" style="display:none"></el-input>
	</div>
</template>

<script>
	import { defineAsyncComponent } from 'vue'
	import COS from 'cos-js-sdk-v5'
	import config from "@/config/upload"
	const scCropper = defineAsyncComponent(() => import('@/components/scCropper'))
	const scFileSelect = defineAsyncComponent(() => import('@/components/scFileSelect'))

	export default {
		props: {
			width: {type: Number, default: 120},
			height: {type: Number, default: 120},
			modelValue: { type: String, default: "" },
			action: { type: String, default: "" },
			apiObj: { type: Object, default: () => {} },
			accept: { type: String, default: "image/gif, image/jpeg, image/png" },
			maxSize: { type: Number, default: config.maxSize },
			title: { type: String, default: "" },
			icon: { type: String, default: "el-icon-plus" },
			fileSelect: { type: Boolean, default: false },
			cropper: { type: Boolean, default: false },
			compress: {type: Number, default: 1},
			aspectRatio:  {type: Number, default: NaN},
			cWidth: {type: Number, default: NaN},
			cHeight: {type: Number, default: NaN},
			onSuccess: { type: Function, default: () => { return true } },
			disabled: { type: Boolean, default: false },
			url: { type: Boolean, default: null }
		},
		components: {
			scCropper,
			scFileSelect
		},
		data() {
			return {
				loading: false,
				fileIsImg: true,
				img: "",
				tempImg: "",
				path: "",
				style: {
					width: this.width + "px",
					height: this.height + "px"
				},
				cropperDialogVisible: false,
				cropperImg: "",
				cropperUploadFile: null,
				fileSelectDialogVisible: false,
				cosapi: null,
				cosdata: {}
			}
		},
		watch:{
			modelValue(){
				this.isImg(this.modelValue)
				if (this.modelValue.indexOf('http') === 0) {
					this.img = this.modelValue
					let relUrl = '' 
					if (this.img) {
						let arrUrl = this.img.split("://");
						let file = arrUrl.length == 1 ? arrUrl[0] : arrUrl[1] 
						let start = file.indexOf("/");
						if (start == -1) {
							start = 0
						}
						relUrl = file.substring(start);

						if (!config.iscos && relUrl.indexOf("/storage/") === 0) {
							relUrl = relUrl.replace("/storage/", "/")
						}
					}
					this.$emit('update:modelValue', relUrl);	
				}
			},
			img(){
				let relUrl = '' 
				if (this.img && typeof(this.img) === 'string') {
					let arrUrl = this.img.split("://");
					let file = arrUrl.length == 1 ? arrUrl[0] : arrUrl[1] 
					let start = file.indexOf("/");
					if (start == -1) {
						start = 0
					}
					relUrl = file.substring(start);

					if (!config.iscos && relUrl.indexOf("/storage/") === 0) {
						relUrl = relUrl.replace("/storage/", "/")
					}
				}
				this.$emit('update:modelValue', relUrl);
			},
			url(){
				this.img = this.url
			},
		},
		mounted() { 
			this.isImg(this.modelValue)
			this.img = this.modelValue
			if (this.url) {
				this.img = this.url
			}
		},
		methods: {
			showfileSelect(){
				this.fileSelectDialogVisible = true
			},
			fileSelectSubmit(val){
				this.img = val
				this.fileSelectDialogVisible = false
			},
			cropperSave(){
				var uploadFile = this.$refs.upload.uploadFiles[0].raw
				this.$refs.cropper.getCropFile(file => {
					this.cropperUploadFile = file
					this.$refs.upload.submit()
				}, uploadFile.name, uploadFile.type)
				this.cropperDialogVisible = false
			},
			isImg(fileUrl){
				var strRegex = "(.jpg|.png|.gif|.jpeg)$";
				var re = new RegExp(strRegex);
				this.fileIsImg=true;
			},
			async cosget(){
				let res = await this.$API.storage.cos.tempsecret.get()
				this.cosapi = new COS({
                    getAuthorization: function (options, callback) {
                        callback({
                            TmpSecretId: res.data.credentials.tmpSecretId,
                            TmpSecretKey: res.data.credentials.tmpSecretKey,
                            XCosSecurityToken: res.data.credentials.sessionToken,
                            ExpiredTime: res.data.expiredTime
                        });
                    }
                })
				this.cosdata = res.data
			},
			change(file){
				if(this.cropper && file.status=='ready'){
					this.isImg(file.name)
					if(!this.fileIsImg){
						this.$notify.warning({
							title: '上传文件警告',
							message: '选择的文件非图像类文件'
						})
						return false
					}
					this.cropperDialogVisible = true
					this.cropperImg = URL.createObjectURL(file.raw)
				}
			},
		    async before(file){
				file = this.cropper ? this.cropperUploadFile : file
				const maxSize = file.size / 1024 / 1024 < this.maxSize;
				if (!maxSize) {
					this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
					return Promise.reject(false);
				}
				this.isImg(file.name)
				this.loading = true;
				if (config.iscos) {
					await this.cosget()
				}
				// this.tempImg = URL.createObjectURL(file);
				this.loading = true;
			},
			success(res) {
				this.loading = false;
				this.tempImg = "";
				var os = this.onSuccess(res);
				if (os != undefined && os == false) {
					return false;
				}
				var response = config.iscos ? config.cosData(res) : config.parseData(res);
				if (response.code != config.successCode) {
					this.$message.warning(response.msg || "上传文件未知错误")
					return false
				}

				this.img = response.src;
				if (config.iscos) {
					let relUrl = ''
					if (this.img) {
						let arrUrl = this.img.split("://");
						let file = arrUrl.length == 1 ? arrUrl[0] : arrUrl[1]
						let start = file.indexOf("/");
						if (start == -1) {
							start = 0
						}
						relUrl = file.substring(start);
					}
					this.$emit('update:modelValue', relUrl);
				} else {
					this.$emit('update:modelValue', response.path);
				}
				this.$emit('update:url', this.img);
			},
			error(err){
				this.$notify.error({title: '上传文件错误', message: err})
				this.loading = false;
				this.tempImg = "";
				this.img = ""
			},
			del(){
				this.img = ""
			},
			request(param) {
				var file = this.cropper ? this.cropperUploadFile : param.file

				if (config.iscos) {
					// 重新定义文件名防止中文
					let uploadFilePath = this.cosdata.tempUploadPath.slice(0, this.cosdata.tempUploadPath.length - 1)
					let uploadFileName = uploadFilePath + "/" + (new Date().getTime()) + '.' + file.type.split("/")[1]

					this.cosapi.putObject({
						Bucket: this.cosdata.bucket,
						Region: this.cosdata.region,
						Key: uploadFileName,
						Body: file
					}, (err, data) => {
						if (!err) {
							console.log(data)
							param.onSuccess(data)
						} else {
							param.onError(err)
						}
					});
				} else {
					let apiObj = config.apiObj
					if (this.apiObj) {
						apiObj = this.apiObj
					}

					const data = new FormData()
					data.append("file", file)
					data.append("type", file.type.split("/")[0])

					apiObj.post(data).then(res => {
						param.onSuccess(res)
					}).catch(err => {
						param.onError(err)
					})
				}
			}
		}
	}
</script>

<style>
	.sc-upload+.sc-upload {margin-left: 10px;}
    .sc-upload .sc-upload-file .image img {object-fit: cover;}
</style>

<style scoped>
	.el-form-item.is-error .sc-upload-uploader {border: 1px dashed #F56C6C;}

	.sc-upload {width: 120px;height: 120px;display: inline-block;vertical-align: top;box-sizing: border-box;}

	.sc-upload-file {position: relative;width: 100%;height: 100%;}
	.sc-upload-file .mask {display: none;position: absolute;top:0px;right:0px;line-height: 1;z-index: 1;}
	.sc-upload-file .mask span {display: inline-block;width: 25px;height:25px;line-height: 23px;text-align: center;cursor: pointer;color: #fff;}
	.sc-upload-file .mask span i {font-size: 12px;}
	.sc-upload-file .mask .del {background: #F56C6C;}
	.sc-upload-file .image {width: 100%;height: 100%;}
	.sc-upload-file .image img {vertical-align: bottom;object-fit: cover;}
	.sc-upload-file .file {width: 100%;height: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;border: 1px solid #DCDFE6;}
	.sc-upload-file .file i {font-size: 30px;color: #409EFF;}
	.sc-upload-file:hover .mask {display: inline-block;}

	.sc-upload-uploader {border: 1px dashed #d9d9d9;box-sizing: border-box;width: 100%;height: 100%;}
	.sc-upload-uploader:hover {border: 1px dashed #409eff;}
	.sc-upload-uploader .uploader {width: 100%;height: 100%;}
	.sc-upload-uploader:deep(.el-upload) {width: 100%;height: 100%;}

	.sc-upload-uploader .file-empty {width: 100%;height: 100%;line-height: 1;display: flex;flex-direction: column;align-items: center;justify-content: center;}
	.sc-upload-uploader .file-empty i {font-size: 28px;color: #8c939d;}
	.sc-upload-uploader .file-empty h4 {font-size: 12px;font-weight: normal;color: #8c939d;margin-top: 10px;}
</style>
